﻿using System;
using System.Data.Entity.Database;
using System.Linq;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NpCrm.DataAccess.Repositories;

namespace NpCrm.Domain.Tests
{
    [TestClass]
    public class SiteContentRepositoryTests
    {
        private TransactionScope _scope;
        [TestInitialize]
        public void TestSetup()
        {
            DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<NpCrm.DataAccess.Core.NpCrmDataContext>());
            _scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                          new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted });
        }

        [TestCleanup]
        public void TestTeardown()
        {
            if (_scope != null)
                _scope.Dispose();
        }

        [TestMethod]
        public void CanAdd()
        {
            AddFakeSiteContent();
        }
        
        [TestMethod]
        public void CanGetById()
        {
            var fakeContent = AddFakeSiteContent();
            using(var contentRepo = new SiteContentRepository())
            {
                var persistedContent = contentRepo.GetById(fakeContent.ContentId);
                Assert.IsNotNull(persistedContent);
                Assert.AreNotSame(fakeContent, persistedContent);
                CompareContent(fakeContent, persistedContent);
            }
        }

        [TestMethod]
        public void CanUpdate()
        {
            var fakeContent = AddFakeSiteContent();
            SiteContent updateContent;
            using (var contentRepo = new SiteContentRepository())
            {
                updateContent = contentRepo.GetById(fakeContent.ContentId);
                updateContent.Name = "updateName";
                updateContent.Value = "updateValue";
                contentRepo.Commit();
            }
            using (var contentRepo = new SiteContentRepository())
            {
                var updatedContent = contentRepo.GetById(updateContent.ContentId);
                Assert.IsNotNull(updatedContent);
                Assert.AreNotSame(updateContent, updatedContent);
                CompareContent(updateContent, updatedContent);
            }
        }

        [TestMethod]
        public void CanDelete()
        {
            var fakeContent = AddFakeSiteContent();
            using (var contentRepo = new SiteContentRepository())
            {
                var contentToDelete = contentRepo.GetById(fakeContent.ContentId);
                contentRepo.Delete(contentToDelete);
                contentRepo.Commit();
            }
            using (var contentRepo = new SiteContentRepository())
            {
                var shouldBeNull = contentRepo.GetById(fakeContent.ContentId);
                Assert.IsNull(shouldBeNull);
            }
        }

        [TestMethod]
        public void CanGetByName()
        {
            var fakeContent = AddFakeSiteContent();
            using (var contentRepo = new SiteContentRepository())
            {
                var persistedContent = contentRepo.GetByName(fakeContent.Name);
                Assert.IsNotNull(persistedContent);
                Assert.AreNotSame(fakeContent, persistedContent);
                CompareContent(fakeContent, persistedContent);
            }
        }

        public static SiteContent AddFakeSiteContent()
        {
            using (var contentRepo = new SiteContentRepository())
            {
                var fakeContent = GetFakeSiteContent();
                contentRepo.Add(fakeContent);
                contentRepo.Commit();
                Assert.IsTrue(fakeContent.ContentId > 0);
                return fakeContent;
            }
        }

        public static void CompareContent(SiteContent expected, SiteContent actual)
        {
            Assert.AreEqual(expected.ContentId, actual.ContentId);
            Assert.AreEqual(expected.Name, actual.Name);
            Assert.AreEqual(expected.Value, actual.Value);
        }

        private static SiteContent GetFakeSiteContent()
        {
            return new SiteContent {Name = "someName", Value = "somePath"};
        }
    }
}
